<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use GatewayWorker\Lib\Gateway;
// use think\facade\Db;
use think\facade\Log;
use Workerman\Timer;
//模型
use Workerman\Worker;
use app\model\ChaozhuoAivideo;
/**
 * Worker 命令行服务类
 */
class Events
{
    /**
     * onWorkerStart 事件回调
     * 当businessWorker进程启动时触发。每个进程生命周期内都只会触发一次
     *
     * @access public
     * @param  \Workerman\Worker    $businessWorker
     * @return void
     */
    public static function onWorkerStart(Worker $businessWorker)
    {
        // echo "onWorkerStart ---SUCCESS\n";
    }

    /**
     * onConnect 事件回调
     * 当客户端连接上gateway进程时(TCP三次握手完毕时)触发
     *
     * @access public
     * @param  int       $client_id
     * @return void
     */
    public static function onConnect($client_id)
    {
        echo 'client_id: ' . $client_id . " is onConnect\n";
        $port = $_SERVER['GATEWAY_PORT'];
        Gateway::sendToCurrentClient("OnConnect: Your client_id is $client_id port is $port");
        Log::write('client_id:' . $client_id, 'chaozhuoTCP');
    }

    /**
     * onWebSocketConnect 事件回调
     * 当客户端连接上gateway完成websocket握手时触发
     *
     * @param  integer  $client_id 断开连接的客户端client_id
     * @param  mixed    $data
     * @return void
     */
    public static function onWebSocketConnect($client_id, $data)
    {
    }

    /**
     * onMessage 事件回调
     * 当客户端发来数据(Gateway进程收到数据)后触发
     *
     * @access public
     * @param  int       $client_id
     * @param  mixed     $data
     * @return void
     */
    public static function onMessage($client_id, $message)
    {
        switch ($_SERVER['GATEWAY_PORT']) {
            case 19000: //控制器链接端口-JSON
                $message = trim($message); // JSON发送
                Log::write($client_id . ': ' . $message, 'chaozhuoTCP');
                // $message = bin2hex($message);//HEX终端设备发送
                // Gateway::sendToCurrentClient('GET: ' . $message); //向当前客户端回复收到的数据
                $message = json_decode($message, true);
                // Log::write($message, 'chaozhuoTCP');
                /* 根据帧类型选择设备与服务器通信命令 */
                switch ($message['mtype'] ?? null) {
                    case 1: //帧类型 设备注册请求帧上传
                        if ($message['token'] == 'czdz') {
                            Gateway::bindUid($client_id, $message['eid']); //绑定wokerman_UID
                            Gateway::sendToCurrentClient('"msg":"ok"}');
                        } else {
                            Log::write($message, 'chaozhuoTCP');
                            Gateway::sendToCurrentClient('{"msg":"err"}');
                        }
                        break;
                    case 2: //塔机设备AI视频记录
                        break;
                    case 3: //主站端主动获取固有参数
                        $aid = $message['aid'];
                        $channel = $message['channel'];
                        $attribute = 'channel_' . $channel . '_switch';
                        $where[] = ['id', '=', $aid];
                        $ChaozhuoAivideo = ChaozhuoAivideo::where($where)->find();
                        if ($ChaozhuoAivideo) {
                            $ChaozhuoAivideo->$attribute =1;
                            $ChaozhuoAivideo->save();
                            Gateway::sendToCurrentClient('{"msg":"ok"}');
                        } else {
                            Gateway::sendToCurrentClient('{"msg":"err"}');
                        }
                        break;
                    case 4: //实时数据上传主站
                    case 5: //实时数据(报警)上传主站
                    case 6: //向设备获取实时数据后的回复
                        $imei = Gateway::getUidByClientId($client_id);
                        // Log::channel('workerman')->debug('case 4 5 6: imei: ' . $imei);
                        $SolarRealtime = new SolarRealtime;
                        $SolarRealtime->imei = $imei;
                        $SolarRealtime->mtype = $message['mtype'];
                        $SolarRealtime->bv = $message['bv'];
                        $SolarRealtime->bi = $message['bi'];
                        $SolarRealtime->pv = $message['pv'];
                        $SolarRealtime->pi = $message['pi'];
                        $SolarRealtime->lv = $message['lv'];
                        $SolarRealtime->li = $message['li'];
                        $SolarRealtime->csq = $message['csq'];
                        $SolarRealtime->dtp = $message['dtp'];
                        $SolarRealtime->btp = $message['btp'];
                        $SolarRealtime->bts = $message['bts'];
                        $SolarRealtime->bvs = $message['bvs'];
                        $SolarRealtime->chs = $message['chs'];
                        $SolarRealtime->lds = $message['lds'];
                        $SolarRealtime->lsw = $message['lsw'];
                        $SolarRealtime->cwh = $message['cwh'];
                        $SolarRealtime->dwh = $message['dwh'];
                        $SolarRealtime->p_power = $message['pv'] * $message['pi'];
                        $SolarRealtime->l_power = $message['lv'] * $message['li'];
                        //计算电量
                        $SolarEquipment = SolarEquipment::firstWhere('imei', $imei);
                        if ($SolarEquipment) {
                            $denominator = $SolarEquipment->op - $SolarEquipment->od;
                        } else {
                            Log::channel('workerman')->debug('IMEI: ' . $imei . '设备不存在');
                            Gateway::closeClient($client_id);
                            break;
                        }
                        if ($denominator != 0) {
                            $quantity = (($message['bv'] - $SolarEquipment->od) / $denominator) * 100;
                            // 确保$quantity在0到100之间
                            $quantity = max(0, min($quantity, 100));
                            $SolarEquipment->quantity = $quantity;
                            $SolarRealtime->quantity = $quantity;
                        } else {
                            $SolarEquipment->quantity = 0; // 或者其他合适的默认值
                            $SolarRealtime->quantity = 0; // 或者其他合适的默认值
                        }
                        $re = $SolarRealtime->save();
                        if ($re && $message['mtype'] != 6) { //mtype6不需要回复 否则触发循环
                            Gateway::sendToCurrentClient('{"mtype":' . $message['mtype'] . ',"msg":"ok"}');
                        }
                        if ($message['mtype'] == 5) { //生成报警信息
                            $bts_alarm = [ //蓄电池温度状态
                                0 => '正常', 1 => '电池充电超温', 2 => '电池放电超温',
                            ];
                            $bvs_alarm = [ //蓄电池电压状态
                                0 => '正常', 1 => '超压(关充电，关负载)', 2 => '欠压(低于低压恢复高于低压保护)', 3 => '过放(低压保护)',
                            ];
                            $lds_alarm = [ //负载放电状态
                                0 => '正常', 1 => '过流保护(电流)', 2 => '短路保护(电流)', 3 => '超温(设备温度)',
                            ];
                            if (isset($message['bts']) && $message['bts'] != 0) {
                                $title = '蓄电池温度状态报警';
                                $content = $bts_alarm[$message['bts']];
                            } elseif (isset($message['bvs']) && $message['bvs'] != 0) {
                                $title = '蓄电池电压状态报警';
                                $content = $bvs_alarm[$message['bvs']];
                            } elseif (isset($message['lds']) && $message['lds'] != 0) {
                                $title = '负载放电状态报警';
                                $content = $lds_alarm[$message['lds']];
                            } else {
                                $title = '其他';
                                $content = '其他报警';
                            }
                            $SolarMessage = new SolarMessage;
                            $SolarMessage->imei = $imei;
                            $SolarMessage->title = $title;
                            $SolarMessage->content = $content;
                            $SolarMessage->visible_users = $SolarEquipment->edit_permission;
                            $SolarMessage->ename = $SolarEquipment->ename;
                            $SolarMessage->sn = $SolarEquipment->sn;
                            $SolarMessage->pv = $SolarRealtime->pv;
                            $SolarMessage->pi = $SolarRealtime->pi;
                            $SolarMessage->lv = $SolarRealtime->lv;
                            $SolarMessage->li = $SolarRealtime->li;
                            $SolarMessage->bv = $SolarRealtime->bv;
                            $SolarMessage->bi = $SolarRealtime->bi;
                            $SolarMessage->p_power = $SolarRealtime->p_power;
                            $SolarMessage->l_power = $SolarRealtime->l_power;
                            $SolarMessage->dtp = $SolarRealtime->dtp;
                            $SolarMessage->btp = $SolarRealtime->btp;
                            $SolarMessage->quantity = $SolarRealtime->quantity;
                            $SolarMessage->save();
                            $SolarEquipment->abnormal_status = 1;
                        }
                        if ($message['mtype'] == 4) {
                            $SolarEquipment->abnormal_status = 0;
                        }
                        $re = $SolarEquipment->save();
                        break;
                    case 7: //设备端向主站发送首次定位数据
                        $imei = Gateway::getUidByClientId($client_id);
                        $SolarEquipment = SolarEquipment::firstWhere('imei', $imei);
                        unset($message['mtype']); // 删除键值对
                        if ($SolarEquipment) {
                            $re = $SolarEquipment->update($message);
                            // if ($re) {
                            // 设置一个定时器，1秒后执行
                            Timer::add(1, function ($client_id) {
                                Gateway::sendToClient($client_id, '{"mtype":7,"msg":"ok"}');
                            }, [$client_id], false); // 最后一个参数为 false，表示只执行一次
                            // }
                        }
                        break;
                    case 8: //主站请求设备端定位数据的回复
                        break;
                    case 9: //远程升级收到设备的回复
                        $SolarEquipment = SolarEquipment::firstWhere('client_id', $client_id);
                        $SolarEquipment->update_error = $message['msg'];
                        $re = $SolarEquipment->save();
                        break;
                    case 10: //终端设备数据转发
                    case 11: //手动负载开关设置
                    case 12: //负载工作模式设置
                        if ($message['msg'] == 'ok') {
                            $imei = Gateway::getUidByClientId($client_id);
                            $SolarEquipment = SolarEquipment::firstWhere('imei', $imei);
                            unset($message['msg'], $message['mtype']); // 删除键值对
                            $message['update_error'] = 'update_ok';
                            if ($SolarEquipment) {
                                $SolarEquipment->update($message);
                            }
                        }
                        break;
                    case 13: //心跳
                        break;
                    default:
                        Gateway::sendToCurrentClient("Default-Type:Your Type is NULL");
                        break;
                }
                break;
            default:
                Gateway::sendToCurrentClient("Default:Your GATEWAY_PORT is " . $_SERVER['GATEWAY_PORT']);
                break;
        }
    }

    /**
     * onClose 事件回调 当用户断开连接时触发的方法
     *
     * @param  integer $client_id 断开连接的客户端client_id
     * @return void
     */
    public static function onClose($client_id)
    {
        echo 'client_id: ' . $client_id . " is onClose\n";
        // $SolarEquipment = SolarEquipment::firstWhere('client_id', $client_id);
        // if ($SolarEquipment) {
        //     $SolarEquipment->online = 0;
        //     $SolarEquipment->client_id = null; //清除client_id
        //     $re = $SolarEquipment->save();
        // }
    }

    /**
     * onWorkerStop 事件回调
     * 当businessWorker进程退出时触发。每个进程生命周期内都只会触发一次。
     *
     * @param  \Workerman\Worker    $businessWorker
     * @return void
     */
    public static function onWorkerStop(Worker $businessWorker)
    {
        // echo "WorkerStop\n";
    }
    public static function formatLogMessage($message)
    {
        $head = substr($message, 0, 4); //帧头
        $length = substr($message, 4, 2); // 帧长度 全部长度总和
        $factory_code = substr($message, 6, 2); // 厂家编号
        $edition = substr($message, 8, 2); // 协议版本
        $type = substr($message, 10, 2); // 帧类型
        $eid = substr($message, 12, 8); //设备ID
        $info = substr($message, 20, -8); // 信息段
        // $info = hex2bin($info);//转换为原始二进制数据
        // $info = json_decode($info);
        $end = substr($message, -8); //帧尾
        return "HEAD:$head\nLEN:$length\nFCODE:$factory_code\nEDITION:$edition\nTYPE:$type\nEID:$eid\nINFO:$info\nEND:$end";
    }
}
